<script lang="tsx">
import { defineComponent, PropType, computed, h, unref } from 'vue'
import { propTypes } from '@/utils/propTypes'

// 工具函数：转义正则特殊字符
const escapeRegExpSpecialChars = (str: string) => {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

export default defineComponent({
  name: 'Highlight',
  props: {
    tag: propTypes.string.def('span'),
    keys: {
      type: Array as PropType<string[]>,
      default: () => []
    },
    color: propTypes.string.def('var(--el-color-primary)'),
    pointer: propTypes.bool.def(false)
  },
  emits: ['click'],
  setup(props, { emit, slots }) {
    // 过滤空关键词，避免空匹配
    const validKeys = computed(() =>
      props.keys.filter(key => typeof key === 'string' && key.trim() !== '')
    )

    const keyNodes = computed(() => {
      // 直接遍历数组，更简洁直观
      return validKeys.value.map((key, _index) => {
        return h(
          'span',
          {
            onClick: () => {
              if (props.pointer) {
                emit('click', key)
              }
            },
            style: {
              color: props.color,
              cursor: props.pointer ? 'pointer' : 'default',
              fontWeight: '500'
            }
          },
          key
        )
      })
    })

    const parseText = (text: string) => {
      let result = text
      // 1. 为避免替换冲突，使用特殊标记（包含随机字符串）
      const randomStr = Math.random().toString(36).substring(2, 8)
      const startMarker = `__HIGHLIGHT_START_${randomStr}__`
      const endMarker = `__HIGHLIGHT_END_${randomStr}__`

      // 2. 转义关键词中的特殊字符，避免正则错误
      validKeys.value.forEach((key, index) => {
        const escapedKey = escapeRegExpSpecialChars(key)
        const regexp = new RegExp(escapedKey, 'g')
        result = result.replace(regexp, `${startMarker}${index}${endMarker}`)
      })

      // 3. 分割文本为普通文本和高亮标记
      return result.split(new RegExp(`${startMarker}|${endMarker}`))
    }

    const renderText = () => {
      if (!slots?.default) return null

      // 获取插槽文本内容
      const slotContent = slots.default()[0]
      const textContent = slotContent?.children as string

      if (!textContent) {
        return slotContent
      }

      // 解析文本并生成节点
      const textArray = parseText(textContent)
      const regexp = /^[0-9]+$/
      const nodes = textArray.map((segment) => {
        // 数字段表示关键词索引
        if (regexp.test(segment) && !isNaN(Number(segment))) {
          const index = Number(segment)
          return unref(keyNodes)[index] || segment
        }
        return segment
      })

      return h(props.tag, nodes)
    }

    return () => renderText()
  }
})

</script>
